#include "head.h"

int size, max_size;
time_t time_var;
int file_des;

#ifdef SYSTEMV
int queue_id;
#else
mqd_t queue_id;
#endif

void cleanup() {
#ifdef SYSTEMV
	if (msgctl(queue_id, IPC_RMID, NULL) == -1) {
		perror("msgctl");
	}
	if (unlink(SERVER_FILE) == -1) {
		perror("unlink");
	}
#else
	if (mq_close(queue_id) == -1) {
		perror("mq_close");
	}
	if (mq_unlink(SERVER_FILE) == -1) {
		perror("mq_unlink");
	}
#endif
	if (close(file_des) == -1) {
		perror("output file");
	}
}

void sig_int(int signo) {
	printf("Shutting server down\n");
	exit(0);
}

void create_queue(char * path,
#ifdef SYSTEMV
	int type, int * queue_id
#else
	mqd_t * queue_id
#endif
) {
#ifdef SYSTEMV
	if (close(open(path, O_CREAT | O_RDONLY | O_EXCL, 0666)) == -1) {
		perror("create");
		exit(-5);
	}
	key_t queue_key;
	if ((queue_key = ftok(path, type)) == -1) {
		perror("ftok");
		exit(-6);
	}
	if ((*queue_id = msgget(queue_key, IPC_CREAT | IPC_EXCL | 0666)) == -1) {
		perror("msgget");
		exit(-7);
	}
#else
	struct mq_attr queue_attr;
	queue_attr.mq_msgsize = sizeof(struct message);
	queue_attr.mq_flags = 0;
	queue_attr.mq_maxmsg = 10;
	if ((*queue_id = mq_open(path, O_CREAT | O_EXCL | O_RDONLY, 0666, &queue_attr)) == -1) {
		perror("mq_open");
		exit(-5);
	}
#endif
}
#ifdef POSIX_SIGNAL	
void message_rcv(int sig) {
	struct message mess;
	if (size <= max_size) {
		if (mq_receive(queue_id, (char *)&mess, sizeof(struct message), NULL) == -1) {
			perror("mq_receive");
			exit(-1);
		}
		time(&time_var);
		char * mess_out = (char *)malloc(sizeof(char)*(MESS_LENGTH + NICK_LENGTH + TIME_LENGTH + 5));
		sprintf(mess_out, "%s: %s: %s\n", mess.nick, ctime(&time_var), mess.msg);
		mess_out[strlen(mess_out)-1] = '\0';
		if (size + strlen(mess_out) <= max_size) {
			int tmp;
			if ((tmp = write(file_des, mess_out, strlen(mess_out))) == -1) {
				perror(OUTPUT);
				exit(-2);
			}
			size += tmp;
			kill(mess.pid, SIGUSR2);
		} else {
			kill(mess.pid, SIGUSR1);
		}
		free(mess_out);
	} else {
		if (mq_receive(queue_id, (char *)&mess, sizeof(struct message), NULL) == -1) {
			perror("mq_receive");
			exit(-3);
		}
		kill(mess.pid, SIGUSR1);
	}
	struct sigevent event;
	event.sigev_signo = SIGUSR1;
	event.sigev_notify = SIGEV_SIGNAL;
	mq_notify(queue_id, &event);
}
#endif


int main(int argc, char ** argv) {
	if (argc != 2) {
		printf("Niepoprawne wywołanie. Poprawne wywołanie: ./server.o <maksymalny_rozmiar_pliku>.\n");
		return -1;
	}
	if ((file_des = open(OUTPUT, O_CREAT | O_WRONLY | O_TRUNC, 0666)) == -1) {
		perror(OUTPUT);
		return -2;
	}
	max_size = atoi(argv[1]);
	if (max_size <= 0) {
		printf("Maksymalny rozmiar pliku musi być liczbą całkowitą dodatnią.\n");
		return -3;
	}
	atexit(cleanup);
#ifdef SYSTEMV
	create_queue(SERVER_FILE, SERVER, &queue_id);
#elif POSIX
	create_queue(SERVER_FILE, &queue_id);
#elif POSIX_SIG
	create_queue(SERVER_FILE, &queue_id);
	if (signal(SIGUSR1, message_rcv) == SIG_ERR) {
		perror("signal");
		return -4;
	}
	struct sigevent event;
	event.sigev_notify = SIGEV_SIGNAL;
	event.sigev_signo = SIGUSR1;
	mq_notify(queue_id, &event);
#endif
	if (signal(SIGINT, sig_int) == SIG_ERR) {
		perror("signal");
		return -5;
	}
#if defined SYSTEMV || defined POSIX
	struct message mess;
	size = 0;
	char * mess_out = (char *)malloc(sizeof(char)*(MESS_LENGTH + NICK_LENGTH + TIME_LENGTH + 5));
	while (size < max_size) {
	#ifdef POSIX
		if (mq_receive(queue_id, (char *)&mess, sizeof(struct message), NULL) == -1) {
			perror("mq_receive");
			return -6;
		}
	#elif SYSTEMV
		if (msgrcv(queue_id, &mess, sizeof(struct message), CLIENT, 0) == -1) {
			perror("msgrcv");
			return -6;
		}
	#endif
		time(&time_var);
		sprintf(mess_out, "%s: %s: %s\n", mess.nick, ctime(&time_var), mess.msg);
		mess_out[strlen(mess_out)-strlen(mess.msg)-4] = ' ';
		mess_out[strlen(mess_out)] = '\0';
		int tmp;
		if (size + strlen(mess_out) <= max_size) {
			if ((tmp = write(file_des, mess_out, strlen(mess_out))) == -1) {
				perror("write");
				return -7;
			}
			size += tmp;
			kill(mess.pid, SIGUSR2);
		} else {
			kill(mess.pid, SIGUSR1);
		}
	}
	while(1) {	
	#ifdef POSIX
		if (mq_receive(queue_id, (char *)&mess, sizeof(struct message), NULL) == -1) {
			perror("mq_receive");
			return -8;
		}
	#elif SYSTEMV
		if (msgrcv(queue_id, &mess, sizeof(struct message), CLIENT, 0) == -1) {
			perror("msgrcv");
			return -9;
		}
	#endif
		kill(mess.pid, SIGUSR1);
	}
	free(mess_out);
#elif POSIX_SIGNAL
	while(1) {
		sleep(5);
	}
#endif
	return 0;
}
